package com.zy;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @description: 测试类加载器
 * @author: zhaoyi
 * @create: 2019-12-08 21:34
 * <p>
 * 注意
 * 重写的是findClass方法不是loadClass
 * <p>
 * 参考javadoc中的示例
 * * <blockquote><pre>
 *  *     class NetworkClassLoader extends ClassLoader {
 *  *         String host;
 *  *         int port;
 *  *
 *  *         public Class findClass(String name) {
 *  *             byte[] b = loadClassData(name);
 *  *             return defineClass(name, b, 0, b.length);
 *  *         }
 *  *
 *  *         private byte[] loadClassData(String name) {
 *  *             // load the class data from the connection
 *  *             &nbsp;.&nbsp;.&nbsp;.
 *  *         }
 *  *     }
 *  * </pre></blockquote>
 **/

public class TestClassLoader extends ClassLoader {

    private String path;

    public void setPath(String path) {
        this.path = path;
    }

    /**
     * 制定父类加载器
     *
     * @param parent
     */
    public TestClassLoader(ClassLoader parent) {
        super(parent);
    }

    /**
     * 不指定父类加载，默认是系统类加载器（也叫应用类加载器）
     * <tt>getSystemClassLoader()</tt>} as the parent class loader.
     */
    public TestClassLoader() {
        super();
    }

    /**
     * 重写的是findClass方法不是loadClass
     * 通过类的全类名找到对应byte数组，调用defineClass将数组转换成class对象
     *
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] bytes = loadClassData(name);
        Class<?> aClass = defineClass(name, bytes, 0, bytes.length);
        System.out.println("loadClass " + name );
        return aClass;
    }

    private byte[] loadClassData(String name) {
        name = name.replace(".", "\\");
        File file = new File(path + name + ".class");
        return getFileByteArray(file);
    }

    public static byte[] getFileByteArray(File file) {
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            System.out.println("file too big...");
            return null;
        }
        byte[] buffer = null;
        try (FileInputStream fi = new FileInputStream(file)) {
            buffer = new byte[(int) fileSize];
            int offset = 0;
            int numRead = 0;
            while (offset < buffer.length
                    && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
                offset += numRead;
            }
            // 确保所有数据均被读取
            if (offset != buffer.length) {
                throw new IOException("Could not completely read file "
                        + file.getName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return buffer;
    }


}
